/**
 * 前端输入清理和XSS防护工具
 */

export class InputSanitizer {
  private static instance: InputSanitizer;
  
  private readonly xssPatterns = [
    /<script[^>]*>.*?<\/script>/gis,
    /<iframe[^>]*>.*?<\/iframe>/gis,
    /<object[^>]*>.*?<\/object>/gis,
    /<embed[^>]*>.*?<\/embed>/gis,
    /<link[^>]*>/gis,
    /<meta[^>]*>/gis,
    /<style[^>]*>.*?<\/style>/gis,
    /javascript:/gis,
    /on\w+\s*=/gis,
  ];
  
  private readonly dangerousAttributes = [
    'onclick', 'onload', 'onerror', 'onmouseover', 'onmouseout',
    'onfocus', 'onblur', 'onchange', 'onsubmit', 'onreset',
    'onselect', 'onkeydown', 'onkeyup', 'onkeypress', 'onabort'
  ];
  
  public static getInstance(): InputSanitizer {
    if (!InputSanitizer.instance) {
      InputSanitizer.instance = new InputSanitizer();
    }
    return InputSanitizer.instance;
  }
  
  /**
   * 清理字符串内容，移除XSS攻击向量
   */
  public sanitizeString(input: string, maxLength: number = 50000): string {
    if (!input || typeof input !== 'string') {
      return '';
    }
    
    // 长度限制
    let sanitized = input.slice(0, maxLength);
    
    // 移除控制字符（除了常见的空白字符）
    sanitized = sanitized.replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, '');
    
    // HTML实体解码（简单版本）
    sanitized = sanitized
      .replace(/&lt;/g, '<')
      .replace(/&gt;/g, '>')
      .replace(/&amp;/g, '&')
      .replace(/&quot;/g, '"')
      .replace(/&#x27;/g, "'");
    
    // 移除XSS模式
    for (const pattern of this.xssPatterns) {
      sanitized = sanitized.replace(pattern, '');
    }
    
    // 移除危险属性
    for (const attr of this.dangerousAttributes) {
      const attrPattern = new RegExp(`${attr}\\s*=\\s*["'][^"']*["']`, 'gis');
      sanitized = sanitized.replace(attrPattern, '');
    }
    
    return sanitized.trim();
  }
  
  /**
   * 验证提示词内容是否安全
   */
  public validatePromptContent(content: string): { isValid: boolean; issues: string[] } {
    const issues: string[] = [];
    
    if (!content) {
      return { isValid: true, issues: [] };
    }
    
    // 检查XSS攻击
    for (const pattern of this.xssPatterns) {
      if (pattern.test(content)) {
        issues.push('检测到潜在的XSS攻击脚本');
        break;
      }
    }
    
    // 检查危险属性
    for (const attr of this.dangerousAttributes) {
      const attrPattern = new RegExp(`${attr}\\s*=`, 'i');
      if (attrPattern.test(content)) {
        issues.push(`检测到危险的事件属性: ${attr}`);
      }
    }
    
    // 检查长度
    if (content.length > 50000) {
      issues.push('内容长度超出限制（50000字符）');
    }
    
    // 检查恶意URL模式
    if (/javascript:|data:|vbscript:/i.test(content)) {
      issues.push('检测到危险的URL协议');
    }
    
    return {
      isValid: issues.length === 0,
      issues
    };
  }
  
  /**
   * 清理HTML内容，保留安全的标签
   */
  public sanitizeHtml(html: string): string {
    if (!html) return '';
    
    // 允许的安全标签
    const allowedTags = ['p', 'br', 'b', 'i', 'u', 'strong', 'em', 'span', 'div'];
    
    // 移除所有不在白名单中的标签
    let sanitized = html.replace(/<([^>]+)>/g, (match, tagContent) => {
      const tagName = tagContent.split(' ')[0].toLowerCase();
      if (allowedTags.includes(tagName)) {
        // 移除标签中的危险属性
        let cleanTag = tagContent;
        for (const attr of this.dangerousAttributes) {
          const attrPattern = new RegExp(`\\s+${attr}\\s*=\\s*["'][^"']*["']`, 'gis');
          cleanTag = cleanTag.replace(attrPattern, '');
        }
        return `<${cleanTag}>`;
      }
      return ''; // 移除不安全的标签
    });
    
    return sanitized;
  }
  
  /**
   * 清理变量名，确保安全性
   */
  public sanitizeVariableName(name: string): string {
    if (!name) return '';
    
    // 只允许字母、数字、下划线和连字符
    return name.replace(/[^a-zA-Z0-9_-]/g, '').slice(0, 50);
  }
  
  /**
   * 清理对象中的所有字符串字段
   */
  public sanitizeObject<T extends Record<string, any>>(obj: T): T {
    const sanitized = { ...obj };
    
    for (const [key, value] of Object.entries(sanitized)) {
      if (typeof value === 'string') {
        sanitized[key] = this.sanitizeString(value);
      } else if (Array.isArray(value)) {
        sanitized[key] = value.map(item => 
          typeof item === 'string' ? this.sanitizeString(item) : 
          typeof item === 'object' ? this.sanitizeObject(item) : item
        );
      } else if (typeof value === 'object' && value !== null) {
        sanitized[key] = this.sanitizeObject(value);
      }
    }
    
    return sanitized;
  }
}

// 导出单例实例
export const inputSanitizer = InputSanitizer.getInstance();